

#include <stdint.h>
#include <phApp_Init.h>
#include <phNfcLib_Int.h>
#include <phNfcLib_Initialization.h>
#include <Debug.h>
#include "ipcMessage.h"
#include <Reader/Reader.h>
#include "Log.h"

#if !defined(NDEBUG)
#define HID_RF_LOG_BUF(fmt, buf, len)		Log_Buf(0, RTT_CTRL_TEXT_BRIGHT_WHITE, buf, len, 200, fmt)
#else
#define HID_RF_LOG_BUF(fmt, buf, len)		
#endif

static uint8_t tclFlag;

int HID_RF_SetDataFormatFlags(uint16_t flags, uint8_t lastBits){
 	void * hal = phNfcLib_GetDataParams(PH_COMP_HAL);
	phStatus_t status;
	uint16_t wValue;
	uint8_t parity = PH_OFF;
	uint8_t tx_crc = PH_OFF;
	uint8_t rx_crc = PH_OFF;
	
//		LOG_I("flag: 0x%04X, lastBits: %02X", flags, lastBits);
	
	if(flags != 0x0000){
		if(flags & ASN1_RF_FLAGS_TX_ONLY_SOF){
			LOG_W("ASN1_RF_FLAGS_TX_ONLY_SOF not support!");
		}
		if(flags & ASN1_RF_FLAGS_TX_ONLY_EOF){
			LOG_W("ASN1_RF_FLAGS_TX_ONLY_EOF not support!");
		}
		if(flags & ASN1_RF_FLAGS_RX_ONLY_SOF){
			LOG_W("ASN1_RF_FLAGS_RX_ONLY_SOF not support!");
		}
		if(flags & ASN1_RF_FLAGS_RX_ONLY_EOF){
			LOG_W("ASN1_RF_FLAGS_RX_ONLY_EOF not support!");
		}
		if(flags & ASN1_RF_FLAGS_RX_NO_SOF){
			LOG_W("ASN1_RF_FLAGS_RX_NO_SOF not support!");
		}
		if(flags & ASN1_RF_FLAGS_RX_NO_EOF){
			LOG_W("ASN1_RF_FLAGS_RX_NO_EOF not support!");
		}
		
		if(flags & (ASN1_RF_FLAGS_RX_PARITY | ASN1_RF_FLAGS_TX_PARITY)){
			parity = PH_ON;
		}
		else
		if(flags & ASN1_RF_FLAGS_PARITY_EVEN){
			parity = PH_ON;
		}
		
		if(flags & ASN1_RF_FLAGS_TX_CRC){
		   tx_crc = PH_ON;
		}
		
		if(flags & ASN1_RF_FLAGS_RX_CRC){
			rx_crc = PH_ON;
		}
	}
	
	PH_CHECK_SUCCESS_FCT(status, phhalHw_GetConfig(hal, PHHAL_HW_CONFIG_RXCRC, &wValue));
	if(rx_crc != wValue){
		PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_RXCRC, rx_crc));
	}
	
	PH_CHECK_SUCCESS_FCT(status, phhalHw_GetConfig(hal, PHHAL_HW_CONFIG_TXCRC, &wValue));
	if(tx_crc != wValue){
		PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_TXCRC, tx_crc));
	}
	
	PH_CHECK_SUCCESS_FCT(status, phhalHw_GetConfig(hal, PHHAL_HW_CONFIG_PARITY, &wValue));
	if(parity != wValue){
		PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_PARITY, parity));
	}
	
	const uint8_t tx_lastBits = lastBits & 0x0F;
	const uint8_t rx_lastBits = (lastBits >> 4) & 0x0F;
	PH_CHECK_SUCCESS_FCT(status, phhalHw_GetConfig(hal, PHHAL_HW_CONFIG_TXLASTBITS, &wValue));
	if(tx_lastBits != wValue){
		PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_TXLASTBITS, tx_lastBits));
	}
	
	PH_CHECK_SUCCESS_FCT(status, phhalHw_GetConfig(hal, PHHAL_HW_CONFIG_RXLASTBITS, &wValue));
	if(rx_lastBits != wValue){
		PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_RXLASTBITS, rx_lastBits));
	}

	return 0;
}

static uint16_t HID_RF_RateConvert(uint8_t ans1_rate){
	uint16_t rate = 0xFFFF;
	
	switch(ans1_rate){
	case ASN1_RF_SPEED_26K:{
		rate = PHHAL_HW_RF_RX_DATARATE_HIGH;
	}
	break;
	case ASN1_RF_SPEED_106K:{
		rate = PHHAL_HW_RF_DATARATE_106;
	}
	break;
	case ASN1_RF_SPEED_212K:{
		rate = PHHAL_HW_RF_DATARATE_212;
	}
	break;
	case ASN1_RF_SPEED_424K:{
		rate = PHHAL_HW_RF_DATARATE_424;
	}
	break;
	case ASN1_RF_SPEED_848K:{
		rate = PHHAL_HW_RF_DATARATE_848;
	}
	break;
	}
	
	return rate;
}


int HID_RF_SetDataRateOut(uint8_t data_rate){
	phStatus_t status;
 	void * hal = phNfcLib_GetDataParams(PH_COMP_HAL);
	LOG_I("rate out: %d", data_rate);
	uint16_t rate = HID_RF_RateConvert(data_rate);
	
	if(rate != 0xFFFF){
		PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_TXDATARATE_FRAMING, rate));
	}
	
	return 0;
}

int HID_RF_SetDataRateIn(uint8_t data_rate){
	phStatus_t status;
 	void * hal = phNfcLib_GetDataParams(PH_COMP_HAL);
	LOG_I("rate in: %d", data_rate);
	uint16_t rate = HID_RF_RateConvert(data_rate);
	if(rate != 0xFFFF){
		PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_RXDATARATE_FRAMING, rate));
	}
	
	return 0;
}

int HID_RF_SetFrameProtocol(uint8_t protocol){
	phStatus_t status;
 	void * hal = phNfcLib_GetDataParams(PH_COMP_HAL);
	LOG_I("protocol: %d", protocol);
	uint16_t cardType = PHHAL_HW_CARDTYPE_ISO15693;
	/* Apply Protocol Setting for Selected Tech  */
	switch(protocol){
	case ASN1_FRAME_PROTOCOL_ISO14443A:{
		cardType = PHHAL_HW_CARDTYPE_ISO14443A;
	}
	break;
	case ASN1_FRAME_PROTOCOL_PICO14443B:{
		cardType = PHHAL_HW_CARDTYPE_ISO14443B;
	}
	break;
	case ASN1_FRAME_PROTOCOL_PICO15693:
	default :{
		cardType = PHHAL_HW_CARDTYPE_ISO15693;
	}
	break;
	}
	
	PH_CHECK_SUCCESS_FCT(status, phhalHw_ApplyProtocolSettings(hal,
		(uint8_t)(cardType & 0xFFU)));
	return 0;
}

uint16_t HID_RF_Init(uint8_t protocol, uint8_t tcl){
	phStatus_t status;
 	void * hal = phNfcLib_GetDataParams(PH_COMP_HAL);
	/* Apply Protocol Setting for Selected Tech  */
	tclFlag = tcl;
	if(tcl != 0){
		return 0;
	}
	HID_RF_SetFrameProtocol(protocol);
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_POLL_GUARD_TIME_US,
		PHAC_DISCLOOP_CONFIG_GTV_VALUE_US));
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_TIMEOUT_VALUE_US,
		500U));
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_RXCRC, PH_OFF));
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_TXCRC, PH_OFF));
	PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_PARITY, PH_OFF));
	return status;
}

void HID_RF_TransceiveSelect(uint8_t tcl){
	tclFlag = tcl;
}

void HID_RF_Deselect(void){
	if(tclFlag){
		LOGD(NULL, "HID_RF_Deselect");
		phpalI14443p4_Deselect(&gphNfcLib_Params.spalI14443p4);
	}
}

void HID_RF_SetFeild(uint8_t state){
 	void * hal = phNfcLib_GetDataParams(PH_COMP_HAL);
	
	if(state){
		phhalHw_FieldOn(hal);
	}
	else{
		phhalHw_FieldOff(hal);
	}
}


static void HID_RF_CommandTranslate(uint8_t *cmd, uint16_t* clen){
	typedef __attribute__((packed, aligned(1))) struct  ApduTag{ 
		uint8_t CLA;
		uint8_t INS;
		uint8_t P1;
		uint8_t P2;
		uint8_t LEN;
		uint8_t DATA[];
	}Apdu_T;
	
	if(reader.dwActivatedType == E_PH_NFCLIB_MIFARE_DESFIRE){
		Apdu_T apdu;
		Apdu_T* papdu = (Apdu_T*)cmd;
		uint8_t* data  = papdu->DATA;
		apdu = *papdu;
		if(apdu.CLA == 0x90){
			uint8_t len = 0;
			cmd[len++] = apdu.INS;
			memcpy(&cmd[len], data, apdu.LEN);
			len += apdu.LEN;
			*clen = len;
		}
	}
}

static void HID_RF_ResponseTranslate(uint8_t* resp, uint16_t *rlen){
	if(reader.dwActivatedType == E_PH_NFCLIB_MIFARE_DESFIRE){
		uint8_t status = resp[0];
		uint8_t len = 0;
		if(*rlen > 1){
			memmove(resp, resp+1, *rlen - 1);
			len = *rlen - 1;
		}
		
		resp[len++] = 0x91;
		resp[len++] = status;

		*rlen = len;
	}
}

uint16_t HID_RF_Transceive(uint8_t *cmd, uint16_t clen, uint8_t* resp, uint16_t *rlen, uint32_t timeout){
	phStatus_t status;
	uint8_t *rx_buf;
	uint16_t rx_len;
	uint32_t t = 0;
	
	
	if(tclFlag){
		HID_RF_CommandTranslate(cmd, &clen);
		void * hal = phNfcLib_GetDataParams(PH_COMP_HAL);
		LOG_TIME();
		LOGD(NULL, "wt=%u", timeout);HID_RF_LOG_BUF("To TAG>", cmd, clen);
		status = phpalI14443p4_Exchange(
			&gphNfcLib_Params.spalI14443p4,
			PH_EXCHANGE_DEFAULT,
			cmd,
			clen,
			&gphNfcLib_State.pRxBuffer,
			&gphNfcLib_State.wRxLength
			);
	
		if(!status){
			*rlen = gphNfcLib_State.wRxLength;
			memcpy(resp, gphNfcLib_State.pRxBuffer, *rlen);
			HID_RF_ResponseTranslate(resp, rlen);
			LOG_TIME();
			HID_RF_LOG_BUF("From TAG<", resp, *rlen);
			return ASN1_RF_STATUS_OK;
		}
	}
	else{
		void * hal = phNfcLib_GetDataParams(PH_COMP_HAL);
		t = timeout+1000;
		PH_CHECK_SUCCESS_FCT(status, phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_TIMEOUT_VALUE_US, t));
		LOG_TIME();
		LOGD(NULL, "wt=%u", t);HID_RF_LOG_BUF("To TAG>", cmd, clen);
		status = phhalHw_Exchange(hal, PH_EXCHANGE_DEFAULT, cmd, clen, &rx_buf, &rx_len);
		if((status & PH_ERR_MASK) == PH_ERR_SUCCESS_INCOMPLETE_BYTE){
			phStatus_t statusTmp;
			uint16_t wValue;
	        PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_GetConfig(hal, PHHAL_HW_CONFIG_RXLASTBITS, &wValue));
			if(wValue != 0){
				LOGD("RXLASTBITS", "%02X", wValue);
				status = PH_ERR_SUCCESS;
			}
		}
		
		if(!status){
			*rlen = rx_len;
			memcpy(resp, rx_buf, *rlen);
			LOG_TIME();
			HID_RF_LOG_BUF("From TAG<", resp, *rlen);
			return ASN1_RF_STATUS_OK;
		}
	}
	LOG_TIME();
	LOG_ERR("RF receive fail: %04X timeout=%d", status, t);
	switch(status & PH_COMPID_MASK){
	case PH_ERR_FRAMING_ERROR: return ASN1_RF_STATUS_FRAMING_ERROR;
	case PH_ERR_COLLISION_ERROR: return ASN1_RF_STATUS_COLLISION;
	case PH_ERR_INTEGRITY_ERROR: return ASN1_RF_STATUS_CRC_ERROR;
	}
	
	return ASN1_RF_STATUS_TIMEOUT;
}

int HID_RF_DoECP(uint8_t expr_tra, uint32_t tb_tci)
{
    phStatus_t  PH_MEMLOC_REM status;
    phStatus_t  PH_MEMLOC_REM statusTmp;
    uint8_t     PH_MEMLOC_REM cmd[10];
	uint8_t 	PH_MEMLOC_REM clen = 0;
    uint8_t *   PH_MEMLOC_REM pResp = NULL;
    uint16_t    PH_MEMLOC_REM wRespLength = 0;
	phpalI14443p3a_Sw_DataParams_t * pDataParams = &gphNfcLib_Params.spalI14443p3a;
	
	(void)phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_TXWAIT_US, 500);
    /* Set halt timeout */
    PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(
        pDataParams->pHalDataParams,
        PHHAL_HW_CONFIG_TIMEOUT_VALUE_US,
        1000));

    PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_TXCRC, PH_ON));
    PH_CHECK_SUCCESS_FCT(statusTmp, phhalHw_SetConfig(pDataParams->pHalDataParams, PHHAL_HW_CONFIG_RXCRC, PH_ON));

    /* Send ECP command */
    cmd[clen++] = 0X6A;
    cmd[clen++] = 0x02;
	cmd[clen++] = expr_tra;
	cmd[clen++] = 0x02;
	memcpy(&cmd[clen], &tb_tci, 4);
	clen += 4;
	
    status = phhalHw_Exchange(pDataParams->pHalDataParams, PH_EXCHANGE_DEFAULT, cmd, clen, &pResp, &wRespLength);

    switch (status & PH_ERR_MASK)
    {
        /* HltA command should timeout -> success */
    case PH_ERR_IO_TIMEOUT:
        return PH_ERR_SUCCESS;
        /* Return protocol error */
    case PH_ERR_SUCCESS:
        return PH_ERR_SUCCESS;
        /* Return other errors */
    default:
        return status;
    }
}

int HID_RF_SelectSeosCard(const uint8_t aid[], uint8_t alen){
	phStatus_t status;
	uint8_t *rx_buf;
	uint16_t rx_len;
	uint8_t cmd[32] = {0x00, 0xA4, 0x04, 0x00, alen,};
	uint16_t clen = 5 + alen;
	memcpy(cmd+5, aid, alen);
	//00 A4 04 00 0A A0 00 00 04 40 00 01 01 00 01
	LOG_TIME();
	HID_RF_LOG_BUF("phpalI14443p4_Exchange cmd_buf", cmd, clen);
	status = phpalI14443p4_Exchange(
		&gphNfcLib_Params.spalI14443p4,
		PH_EXCHANGE_DEFAULT,
		cmd,
		clen,
		&rx_buf,
		&rx_len
		);
	LOG_TIME();
	if(status){
		TRACE_E("phpalI14443p4_Exchange fail: %04X", status);
		return status;
	}
	HID_RF_LOG_BUF("phpalI14443p4_Exchange rx_buf", rx_buf, rx_len);
	if(rx_len < 2){
		TRACE_E("rx_len=%d", rx_len);
		return -1;
	}

	if(rx_buf[rx_len - 2] == 0x90 && rx_buf[rx_len - 1] == 0x00){
		return 0;
	}
	TRACE_E("sw=%02X%02X", rx_buf[rx_len - 2], rx_buf[rx_len - 1]);
	return -2;
}

int HID_RF_CheckSeosCardType(void){
	const uint8_t aidSeos[] = {0xA0, 0x00, 0x00, 0x04, 0x40, 0x00, 0x01, 0x01, 0x00, 0x01};
	const uint8_t aidConfig[] = {0xA0, 0x00, 0x00, 0x03, 0x82, 0x00, 0x13, 0x00, 0x01, 0x01};
	const uint8_t aidAdmin[] = {0xA0, 0x00, 0x00, 0x03, 0x82, 0x00, 0x17, 0x00, 0x01, 0x01};
 	void * hal = phNfcLib_GetDataParams(PH_COMP_HAL);
	uint16_t t;
	phhalHw_SetConfig(hal, PHHAL_HW_CONFIG_TIMEOUT_VALUE_MS, 100);
	phhalHw_GetConfig(hal, PHHAL_HW_CONFIG_TIMEOUT_VALUE_MS, &t);
	TRACE_D("timeout=%d ms", t);
	if(!HID_RF_SelectSeosCard(aidSeos, sizeof(aidSeos))){
		return 1;
	}
	
	if(!HID_RF_SelectSeosCard(aidConfig, sizeof(aidConfig))){
		return 2;
	}
	
	if(!HID_RF_SelectSeosCard(aidAdmin, sizeof(aidAdmin))){
		return 3;
	}
	
	return 0;
}


